/*
 * Scrabble.h
 *
 *  Created on: Jun 28, 2009
 *      Author: mlrus
 */

#ifndef SCRABBLE_H_
#define SCRABBLE_H_

#include <vector>
#include <iterator>
#include <set>
#include <functional>

#include <sstream>
#include <iostream>
#include <ostream>
#include <iomanip>

#include "Common.h"
#include "Axis.h"
#include "Cell.h"
#include "Storable.h"
#include "Dictionary.h"
#include "Util.h"
#include "ExpansionOP.h"
#include "Expander.h"
#include "Board.h"
#include "Result.h"

using namespace std;

class Scrabble {

		static char wordBuffer[Common::boardSize + 1];
		static char validationBuffer[Common::boardSize + 1];

		static int depth;

		static inline bool resultLess(const Result &a, const Result &b) {
			if (a.score != b.score)
				return a.score < b.score;
			int cmp = a.word.compare(b.word);
			if (cmp != 0)
				return cmp < 0;
			if (a.row != b.row)
				return a.row < b.row;
			if (a.col != b.col)
				return a.col < b.col;
			if (a.direction != b.direction)
				return a.direction < b.direction;
			return false;
		}

		struct resultComp {
				bool operator()(const Result& a, const Result& b) {
					return resultLess(a, b);
				}
				~resultComp() { }
		};

		struct ResultLess: public std::binary_function<Result, Result, bool> {
				bool operator()(const Result &a, const Result&b) const {
					return resultLess(a, b);
				}
				~ResultLess() {
				}
		};

		Dictionary dictionary;

		vector<ExpansionOP *> expansionOperatorList;
		vector<Expander *> expanderList;
		vector<Expander *>::iterator expanderIterator;
		set<Result, resultComp> resultList;

	public:
		Board board;
		string rack;
		Scrabble(Dictionary& dictionary, Board& board, string& rack) :
			dictionary(dictionary),
			expansionOperatorList(),
			expanderList(),
			expanderIterator(),
			resultList(),
			board(board),
			rack(rack) {
			expanderList.push_back(new Expander(this, new VerticalExpander()));
			expanderList.push_back(new Expander(this, new HorizontalExpander()));
		}

		virtual ~Scrabble() {
			expanderList.clear();
		}

		const inline bool checkConstraints(const Cell* from, const Cell *to, Axis::Axis axis); // Check if perpendicular run is length=1 or a word
		const bool checkConstraints(const Cell* cell, Axis::Axis axis); // Check if perpendicular run is length=1 or a word

		void addResult(string& word, uint score, uint row, uint col, Axis::Axis direction) {
			Result *res = new Result(word, score, row, col, direction);
			resultList.insert(*res);
		}

		void addResult(const char *str, uint score, uint row, uint col, Axis::Axis direction) {
			addResult(*(new string(str)), score, row, col, direction);
		}
		inline uint testBoardQuick(Cell *from, Cell *to,  Cell *expandLoc, Axis::Axis axis) {
			uint val = 0;
			if (checkWord(from, to, axis)) {
					val = board.scoreMove(expandLoc, axis);
					string *word = new string(getWordbuffer());
					uint row = board.row(from);
					uint col = board.col(from);
					addResult(*word, val, row, col, axis);
			}
			return val;
		}

		void showResults() {
			cout << "Showing results " << resultList.size() << endl;
			int numOut = 0;
			for (set<Result, resultComp>::iterator it = resultList.begin(); it != resultList.end(); it++) {
				cout << it->toString() << endl;
				numOut++;
			}
			cout << "Emitted " << numOut << " items." << endl;
		}
		const Axis::Axis perpendicular(Axis::Axis axis);

		bool checkWord(const Cell *from, const Cell *to, Axis::Axis axis);
		const char* getWordbuffer();

		const uint scoreRange(const Cell* from, const Cell* to); // Score the range (assumes from and to are set correctly, and content is a word)
		void test();
		int evalOne(const Cell* cell, char *nextRack);
		void evalAll();
		void evalAllCostly(); // Depreciated
		void evalMost();      // Depreciated
		int playRecursive(Cell *acceptor, Cell* head, Cell *tail, const char *rack, Axis::Axis axis, int *dirs);
		void showValidChars();
		void initCellChars();
		void initCellChars(Cell *cell, Axis::Axis axis);
};

#endif /* SCRABBLE_H_ */
